Skip to content

feat(review): wire the copycat containment engine into the gate - #5999

Merged
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
oktofeesh1:feat/copycat-detection-engine-1969
Jul 15, 2026
Merged

feat(review): wire the copycat containment engine into the gate#5999
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
oktofeesh1:feat/copycat-detection-engine-1969

Conversation

@oktofeesh1

Copy link
Copy Markdown
Contributor

Summary

  • Implements the copycat/plagiarism containment engine described in Plagiarism / copycat detection #1969: a deterministic shingle-based containment score between a PR's added code and a bounded candidate set of prior art (earlier open siblings + recently-merged PRs on the same repo), with direction resolved by submission timestamp so the earlier (original) author is never flagged.
  • Wires the engine into the gate: gate.copycat.mode (off/warn/label/block, already parsed end-to-end since feat(review): add gate.copycat.mode config scaffold for copycat detection #4140 but previously inert with zero call sites) now actually drives behavior — warn surfaces an advisory finding, label also applies a label without blocking review, block also closes the PR and counts toward a strikes escalation that reuses the existing generic moderation-rules violation ledger (auto-bans/blacklists a repeat offender at the configured threshold, same machinery as blacklist/contributor_cap/review_nag).
  • Closes the exact gap the maintainer's own comment on Plagiarism / copycat detection #1969 identified: "confirmed: copycatGateMode/copycatMode has zero call sites in src/rules/advisory.ts or src/queue/processors.ts."

Scope

  • The PR title follows type(scope): short summary Conventional Commit format, for example fix(api): restore profile access checks.
  • This PR is focused and does not mix unrelated backend, UI, MCP, docs, dependency, and deploy changes.
  • This follows CONTRIBUTING.md and does not reintroduce GitHub Pages, VitePress, site/, or CNAME.
  • I linked a currently open issue this PR resolves (e.g. Closes #123) — a linked open issue is required for every contributor PR.

Validation

  • git diff --check
  • npm run actionlint
  • npm run typecheck
  • npm run test:coverage locally; codecov/patch requires ≥99% coverage of the lines AND branches you changed (aim for 100% on your diff so CI variance does not fail near the threshold). Global coverage is a non-blocking trend with a loose 90% backstop, not the gate.
  • npm run test:workers
  • npm run build:mcp
  • npm run test:mcp-pack
  • npm run ui:openapi:check
  • npm run ui:lint
  • npm run ui:typecheck
  • npm run ui:build
  • npm audit --audit-level=moderate
  • New or changed behavior has unit/integration tests for new branches, fallback paths, and sanitizer boundaries

Ran the full local gate via npm run test:ci (all of the above in one command) — green — plus npm audit --audit-level=moderate (0 vulnerabilities). ~90 new tests across 13 test files (engine primitive: 100% branch coverage; candidate-set builder: 100% branch coverage incl. fail-safe paths; gate/actuation wiring: 16 dedicated tests; a full webhook-simulation integration test proving the score persists end-to-end against a real earlier sibling PR).

Safety

  • No secrets, wallet details, hotkeys, coldkeys, user PATs, private keys, raw trust scores, private rankings, or private maintainer evidence are exposed.
  • Public GitHub text stays sanitized, low-noise, and does not imply compensation guarantees or optimization tactics. The public finding/close/label text only ever cites the matched PR number (already public on GitHub) and containment percentage — never raw code, file paths, or contributor identity.
  • Auth, cookie, CORS, GitHub App, Cloudflare, or session changes include negative-path tests. N/A — no auth/session surface touched.
  • API/OpenAPI/MCP behavior is updated and tested where needed. N/A — no new API/MCP surface; the OpenAPI fields for copycatGateMode/copycatGateMinScore already existed from feat(review): add gate.copycat.mode config scaffold for copycat detection #4140.
  • UI changes use live API data or real empty/error/loading states, not production mock/demo fallbacks. Only two docs pages updated (prose describing the now-live gate tier behavior, replacing stale "config only today" language).
  • Visible UI changes include a UI Evidence section below with JPG/JPEG or PNG screenshots. N/A — docs-page prose only, no visual/layout change.
  • Public docs/changelogs are updated where needed; changelogs are only edited for release-prep PRs. Updated .loopover.yml.example, config/examples/loopover.full.yml, and the two docs.*.tsx pages to remove the now-stale "currently inert" language; did not touch CHANGELOG.md.

If any required check was skipped, explain why:

  • UI Evidence: this PR only edits existing docs-page prose (text describing the gate tier now that it's live), no new component, layout, or visual state.

Notes

  • The false-positive guards from Plagiarism / copycat detection #1969's spec are all enforced: a minimum-shingle floor (3-line window, so a lone brace/return never trips it), a bounded/precision-first candidate set (capped at 25, pre-filtered by changed-file-path overlap before fetching full patch content), lockfile/generated/vendored files excluded from comparison (reusing review-diff.ts's existing diffFilePriority classification), and the containment math itself uses the correct multiset denominator (the exact bug flagged — and since fixed in this PR's own reference implementation — on the prior closed attempt at this issue, feat(signals): add deterministic copycat containment engine for gate.copycat (#1969) #5129).
  • gate.copycat.mode/gate.copycat.minScore remain config-as-code only (no new DB column), consistent with the existing feat(review): add gate.copycat.mode config scaffold for copycat detection #4140 scaffold's design — this PR adds two NEW pull_requests columns (copycat_score, copycat_matched_pull_number) purely to persist the computed assessment for the later actuation pass to read back, mirroring slop_risk/slop_band's exact precedent.

Closes #1969

Implements the deterministic containment/similarity engine gate.copycat.mode
was parsed for since JSONbored#4140 but never acted on. Scores a PR's added lines
against a bounded, precision-first candidate set of earlier open siblings and
recently-merged PRs on the same repo, resolving copy direction by submission
timestamp so the original author is never flagged. warn surfaces an advisory
finding; label also applies a label without blocking review; block also
closes the PR and feeds the existing moderation-rules strikes ledger.

Closes JSONbored#1969
@oktofeesh1
oktofeesh1 requested a review from JSONbored as a code owner July 15, 2026 06:18
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@loopover-orb loopover-orb Bot added gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. gittensor:priority Maintainer-selected Gittensor priority — scores a 1.5x multiplier. labels Jul 15, 2026
@loopover-orb

loopover-orb Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Tip

🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-15 06:34:11 UTC

25 files · 1 AI reviewer · no blockers · readiness 80/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This PR implements the deterministic shingle-based containment engine (packages/loopover-engine/src/signals/copycat.ts + src/queue/copycat-detection.ts) and wires the previously-inert `gate.copycat.mode` into actual gate behavior across agent-actions.ts and processors.ts, with a matching schema+migration for the persisted score/matched-PR columns. The core algorithm (multiset shingle containment, submission-time direction resolution, fail-safe-on-ambiguity) is pure and well-tested in copycat.test.ts, and the bounded candidate-fetch (MAX_COPYCAT_CANDIDATES=25, path-overlap pre-filter before the expensive fetch) matches the PR's own stated 'bounded, fail-safe' design. Direction resolution mixes `createdAt` for open siblings/the candidate PR but `mergedAt` for recently-merged prior art — defensible (merge is when merged code becomes visible) but not documented as an intentional asymmetry.

Nits — 5 non-blocking
  • src/queue/copycat-detection.ts uses `sibling.createdAt` for open-sibling direction but `candidate.mergedAt` for recently-merged prior art's `submittedAt` — worth a one-line comment explaining why merge time (not creation time) is the correct 'became copyable' reference point for merged candidates, since it reads as an inconsistency at first glance.
  • runCopycatAssessment (src/queue/copycat-detection.ts:52-71) awaits `listPullRequestFiles` sequentially inside a loop for up to 25 candidates — bounded so not a blocker, but consider `Promise.all` for latency given this runs synchronously in the gate-evaluation path.
  • The PR description claims block-tier closes 'count toward a strikes escalation that reuses the existing moderation-rules violation ledger' via `closeKind: 'copycat'`, but the actual violation-recording call site that reads `closeKind === 'copycat'` and increments the ledger isn't visible in this diff (only the type/enum additions in moderation-rules.ts are shown) — worth confirming that wiring exists and is exercised by a test.
  • The visible diff shows tests only for the pure engine (copycat.test.ts) and the evidence-collection layer (copycat-detection.test.ts); no test file is shown covering `maybePlanCopycatLabel` or the new block-tier short-circuit in `planAgentMaintenanceActions` (src/settings/agent-actions.ts) — given the diff is truncated at 25 files, confirm agent-actions.ts's ~83 new lines have dedicated coverage.
  • Add a short comment at src/queue/copycat-detection.ts's `submittedAt: candidate.mergedAt` line clarifying the intentional createdAt/mergedAt asymmetry between open and merged prior art.
Signal Result Evidence
Code review ✅ No blockers 1 reviewer
Linked issue ✅ Linked #1969
Related work ⚠️ 2 scoped overlaps Top overlaps are listed below; lower-confidence bulk is hidden.
Change scope ❌ 8/20 High review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 55 registered-repo PR(s), 45 merged, 0 issue(s).
Contributor context ✅ Confirmed Gittensor contributor oktofeesh1; Gittensor profile; 55 PR(s), 0 issue(s).
Gate result ✅ Passing No configured blocker found.
Improvement ✅ Minor risk: clean · value: minor · LLM: significant
Linked issue satisfaction

Addressed
The diff adds a deterministic shingle-based containment engine with timestamp-based direction resolution, wires it into gate.copycat.mode (warn/label/block/strikes) via existing moderation-rules ledger machinery, and includes DB persistence, docs, and a dedicated test file, directly closing the previously-inert plumbing gap described in the issue.

Review context
Contributor next steps
  • Start here: Review top overlaps.
  • Then work through the remaining 2 steps in the Signals table above.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask <question> answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat <question> answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://gittensory.aethereal.dev/docs/loopover-commands

🧪 Experimental — new and may change.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@loopover-orb loopover-orb Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoopOver approves — the gate is satisfied and CI is green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. gittensor:priority Maintainer-selected Gittensor priority — scores a 1.5x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plagiarism / copycat detection

1 participant